﻿using Lazy.Captcha.Core;
using Mapster;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;
using WYD.Common;
using WYD.Infrastructure;
using WYD.Infrastructure.AppConf;
using WYD.Infrastructure.Attribute;
using WYD.Infrastructure.Cache;
using WYD.Infrastructure.Controllers;
using WYD.Infrastructure.Enums;
using WYD.Infrastructure.ExceptionImpl;
using WYD.Infrastructure.Extensions;
using WYD.Infrastructure.Model;
using WYD.Infrastructure.WebExtensions;
using WYD.ServiceCore.Filters;
using WYD.ServiceCore.Model;
using WYD.ServiceCore.Model.Dto;
using WYD.ServiceCore.Services;
using WYD.ServiceCore.Services.IService;

namespace WYD.Admin.WebApi.Controllers.System
{
    /// <summary>
    /// 登录
    /// </summary>
    [ApiExplorerSettings(GroupName = "sys")]
    public class SysLoginController : BaseController
    {
        //static readonly NLog.Logger logger = NLog.LogManager.GetLogger("LoginController");
        private readonly IHttpContextAccessor _httpContextAccessor;
        private readonly ISysUserService _sysUserService;
        private readonly ISysMenuService _sysMenuService;
        private readonly ISysLoginService _sysLoginService;
        private readonly ISysPermissionService _permissionService;
        private readonly ICaptcha _securityCodeHelper;
        private readonly ISysConfigService _sysConfigService;
        private readonly ISysRoleService _roleService;
        private readonly OptionsSetting _optionSettings;

        public SysLoginController(
            IHttpContextAccessor contextAccessor,
            ISysMenuService sysMenuService,
            ISysUserService sysUserService,
            ISysLoginService sysLoginService,
            ISysPermissionService permissionService,
            ISysConfigService configService,
            ISysRoleService sysRoleService,
            ICaptcha captcha,
            IOptions<OptionsSetting> optionSettings)
        {
            _httpContextAccessor = contextAccessor;
            _securityCodeHelper = captcha;
            this._sysMenuService = sysMenuService;
            this._sysUserService = sysUserService;
            this._sysLoginService = sysLoginService;
            this._permissionService = permissionService;
            this._sysConfigService = configService;
            _roleService = sysRoleService;
            this._optionSettings = optionSettings.Value;
        }
        
        // RSA私钥
        private static readonly string PrivatePem = AppSettings.GetConfig("RSA:PrivatePem");
        // RSA公钥
        private static readonly string PublicPem = AppSettings.GetConfig("RSA:PublicPem");

        /// <summary>
        /// 登录
        /// </summary>
        /// <param name="loginBody">登录对象</param>
        /// <returns></returns>
        [Route("login")]
        [HttpPost]
        [Log(Title = "登录")]
        [AllowAnonymous]
        public IActionResult Login([FromBody] LoginBodyDto loginBody)
        {
            if (loginBody == null) { throw new CustomException("请求参数错误"); }
            loginBody.LoginIP = HttpContextExtension.GetClientUserIp(HttpContext);
            var sysConfig = _sysConfigService.GetSysConfigByKey("sys.account.captchaOnOff");
            var headers = HttpContext.Request.Headers;
            var isRemoteInvoke = headers["Remote-Invoke"].FirstOrDefault().ParseToBool();
            if (sysConfig?.ConfigValue != "off" && !_securityCodeHelper.Validate(loginBody.Uuid, loginBody.Code)
                                                && !isRemoteInvoke)
            {
                return ToResponse(ResultCode.CAPTCHA_ERROR, "验证码错误");
            }

            _sysLoginService.CheckLockUser(loginBody.Username);
            string location = HttpContextExtension.GetIpInfo(loginBody.LoginIP);
            
            // RSA解密
            loginBody.Password = Tools.DecryptRSA(PrivatePem, loginBody.Password);
                
            var user = _sysLoginService.Login(loginBody, new SysLogininfor() { LoginLocation = location });

            List<SysRole> roles = _roleService.SelectUserRoleListByUserId(user.UserId);
            //权限集合 eg *:*:*,system:user:list
            List<string> permissions = _permissionService.GetMenuPermission(new SysUserDto { UserId = user.UserId});

            TokenModel loginUser = new(user.Adapt<TokenModel>(), roles.Adapt<List<Roles>>());
            CacheService.SetUserPerms(GlobalConstant.UserPermKEY + user.UserId, permissions);
            
            JwtSettings jwtSettings = new();
            AppSettings.Bind("JwtSettings", jwtSettings);
            
            return SUCCESS(new
            {
                accessToken = JwtUtil.GenerateJwtToken(JwtUtil.AddClaims(loginUser)),
                refreshToken = JwtUtil.GenerateJwtToken(JwtUtil.AddClaims(loginUser), jwtSettings.Expire + 120),
                expires = DateTimeOffset.Now.AddMinutes(jwtSettings.Expire)
            });
        }

        [AllowAnonymous]
        [HttpPost("refresh-token")]
        public IActionResult RefreshToken([FromBody] RefreshTokenBodyDto refreshTokenBodyDto)
        {
            if (refreshTokenBodyDto == null) { throw new CustomException("请求参数错误"); }

            var loginUser = JwtUtil.ValidateJwtToken(JwtUtil.ParseToken(refreshTokenBodyDto.RefreshToken));
            if (loginUser != null)
            {
                var newToken = JwtUtil.GenerateJwtToken(JwtUtil.AddClaims(loginUser));
                JwtSettings jwtSettings = new();
                AppSettings.Bind("JwtSettings", jwtSettings);
                return SUCCESS(new
                {
                    accessToken = newToken,
                    refreshToken = JwtUtil.GenerateJwtToken(JwtUtil.AddClaims(loginUser), jwtSettings.Expire + 120),
                    expires = DateTimeOffset.Now.AddMinutes(jwtSettings.Expire)
                });
            }

            return ToResponse(ApiResult.Error(ResultCode.DENY, "RefreshToken无效"));
        }
        
        /// <summary>
        /// 获取RSA公钥
        /// </summary>
        [HttpGet("getPublicKey")]
        [AllowAnonymous]
        public IActionResult GetPublicKey()
        {
            // 直接返回配置中的公钥字符串
            return SUCCESS(new { publicKey = PublicPem });
        }

        /// <summary>
        /// 注销
        /// </summary>
        /// <returns></returns>
        [Log(Title = "注销")]
        [HttpPost("logout")]
        public IActionResult LogOut()
        {
            //Task.Run(async () =>
            //{
            //    //注销登录的用户，相当于ASP.NET中的FormsAuthentication.SignOut  
            //    await HttpContext.SignOutAsync();
            //}).Wait();
            var userid = HttpContext.GetUId();
            var name = HttpContext.GetName();

            CacheService.RemoveUserPerms(GlobalConstant.UserPermKEY + userid);
            return SUCCESS(new { name, id = userid });
        }

        /// <summary>
        /// 获取用户信息
        /// </summary>
        /// <returns></returns>
        [Verify]
        [HttpGet("getInfo")]
        public IActionResult GetUserInfo()
        {
            long userid = HttpContext.GetUId();
            var user = _sysUserService.SelectUserById(userid);

            //前端校验按钮权限使用
            //角色集合 eg: admin,yunying,common
            List<string> roles = _permissionService.GetRolePermission(user);
            //权限集合 eg *:*:*,system:user:list
            List<string> permissions = _permissionService.GetMenuPermission(user);
            user.WelcomeContent = GlobalConstant.WelcomeMessages[new Random().Next(0, GlobalConstant.WelcomeMessages.Length)];

            return SUCCESS(new { user, roles, permissions });
        }

        /// <summary>
        /// 获取路由信息
        /// </summary>
        /// <returns></returns>
        [Verify]
        [HttpGet("getRouters")]
        public IActionResult GetRouters()
        {
            long uid = HttpContext.GetUId();
            var menus = _sysMenuService.SelectMenuTreeByUserId(uid); 

            return SUCCESS(_sysMenuService.BuildMenus(menus));
        }

        /// <summary>
        /// 生成图片验证码
        /// </summary>
        /// <returns></returns>
        [HttpGet("captchaImage")]
        [AllowAnonymous]
        public IActionResult CaptchaImage()
        {
            string uuid = Guid.NewGuid().ToString().Replace("-", "");

            SysConfig sysConfig = _sysConfigService.GetSysConfigByKey("sys.account.captchaOnOff");
            var captchaOff = sysConfig?.ConfigValue ?? "0";
            var info = _securityCodeHelper.Generate(uuid, 60);
            var obj = new { captchaOff, uuid, img = info.Base64 };// File(stream, "image/png")

            return SUCCESS(obj);
        }

        /// <summary>
        /// 注册
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        [HttpPost("/register")]
        [AllowAnonymous]
        [Log(Title = "注册", BusinessType = BusinessType.INSERT)]
        public IActionResult Register([FromBody] RegisterDto dto)
        {
            SysConfig config = _sysConfigService.GetSysConfigByKey("sys.account.register");
            if (config?.ConfigValue != "true")
            {
                return ToResponse(ResultCode.CUSTOM_ERROR, "当前系统没有开启注册功能！");
            }
            SysConfig sysConfig = _sysConfigService.GetSysConfigByKey("sys.account.captchaOnOff");
            if (sysConfig?.ConfigValue != "off" && !_securityCodeHelper.Validate(dto.Uuid, dto.Code))
            {
                return ToResponse(ResultCode.CAPTCHA_ERROR, "验证码错误");
            }

            SysUser user = _sysUserService.Register(dto);
            if (user.UserId > 0)
            {
                return SUCCESS(user);
            }
            return ToResponse(ResultCode.CUSTOM_ERROR, "注册失败，请联系管理员");
        }

        // /// <summary>
        // /// 发送邮箱验证码
        // /// </summary>
        // /// <param name="sendEmailVo"></param>
        // /// <returns></returns>
        // [HttpPost("getMailCode")]
        // public async Task<IActionResult> GetMailCode([FromBody] SendEmailDto sendEmailVo)
        // {
        //     if (string.IsNullOrEmpty(sendEmailVo.ToUser))
        //     {
        //         return ToResponse(ApiResult.Error($"邮箱不能为空"));
        //     }
        //     if (string.IsNullOrEmpty(optionSettings.MailOptions.FromEmail) || string.IsNullOrEmpty(optionSettings.MailOptions.Password))
        //     {
        //         return ToResponse(ApiResult.Error($"请配置邮箱信息"));
        //     }
        //
        //     if (sendEmailVo.ToUser.Length > 32)
        //     {
        //         // 解密邮箱
        //         sendEmailVo.ToUser = EncryptProvider.RSADecryptWithPem(PrivatePem, sendEmailVo.ToUser);
        //
        //         // 验证邮箱是否存在于系统用户中
        //         var user = await sysUserService.IsAnyAsync(it => it.Email == sendEmailVo.ToUser);
        //         // if (user == null || user.UserId <= 0)
        //         // 不存在则提示错误
        //         if (!user)
        //         {
        //             return ToResponse(ApiResult.Error($"邮箱错误，请联系管理员"));
        //         }
        //
        //     }
        //     else
        //     {
        //         string[] saltKey = await RedisServer.Session.LRangeAsync("saltMail:" + sendEmailVo.ToUser, 0, 1);
        //         if (saltKey.Length > 0)
        //         {
        //             sendEmailVo.ToUser = saltKey[0];
        //         }
        //         else
        //         {
        //             return ToResponse(ApiResult.Error($"邮箱错误，请联系管理员"));
        //         }
        //     }
        //     // 实例化MailHelper以准备发送邮件
        //     MailHelper mailHelper = new();
        //     // 生成6位邮箱验证码
        //     var verifyCode = mailHelper.VerifyCode(6);
        //     // 设置存入Redis的key为 verifyCode: 前缀 + （盐 + 邮箱）的MD5值
        //     var key = "verifyCode:" + sendEmailVo.ToUser;
        //     // 存入Redis中设置过期时间为15分钟
        //     var res = await RedisServer.Session.SetAsync(key, verifyCode, 900);
        //     // 发送邮件，主题为 ZRAdmin.NET邮箱验证码，内容为验证码
        //     mailHelper.SendMail(sendEmailVo.ToUser, "ZRAdmin.NET邮箱验证码", verifyCode);
        //
        //     return SUCCESS(res);
        // }
        
        #region 二维码登录

        /// <summary>
        /// 生成二维码
        /// </summary>
        /// <param name="uuid"></param>
        /// <param name="deviceId"></param>
        /// <returns></returns>
        [HttpGet("/GenerateQrcode")]
        public IActionResult GenerateQrcode(string uuid, string deviceId)
        {
            var state = Guid.NewGuid().ToString();
            var dict = new Dictionary<string, object>
            {
                { "state", state }
            };
            CacheService.SetScanLogin(uuid, dict);
            return SUCCESS(new
            {
                status = 1,
                state,
                uuid,
                codeContent = new { uuid, deviceId }// "https://qm.qq.com/cgi-bin/qm/qr?k=kgt4HsckdljU0VM-0kxND6d_igmfuPlL&authKey=r55YUbruiKQ5iwC/folG7KLCmZ++Y4rQVgNlvLbUniUMkbk24Y9+zNuOmOnjAjRc&noverify=0"
            });
        }

        // /// <summary>
        // /// 轮询判断扫码状态
        // /// </summary>
        // /// <param name="dto"></param>
        // /// <returns></returns>
        // [HttpPost("/VerifyScan")]
        // [AllowAnonymous]
        // public IActionResult VerifyScan([FromBody] ScanDto dto)
        // {
        //     int status = -1;
        //     object token = string.Empty;
        //     if (CacheService.GetScanLogin(dto.Uuid) is Dictionary<string, object> str)
        //     {
        //         status = 0;
        //         str.TryGetValue("token", out token);
        //         if (str.ContainsKey("status") && (string)str.GetValueOrDefault("status") == "success")
        //         {
        //             status = 2;//扫码成功
        //             CacheService.RemoveScanLogin(dto.Uuid);
        //         }
        //     }
        //
        //     return SUCCESS(new { status, token });
        // }

        // /// <summary>
        // /// 移动端扫码登录
        // /// </summary>
        // /// <param name="dto"></param>
        // /// <returns></returns>
        // [HttpPost("/ScanLogin")]
        // [Log(Title = "扫码登录")]
        // [Verify]
        // public IActionResult ScanLogin([FromBody] ScanDto dto)
        // {
        //     if (dto == null) { return ToResponse(ResultCode.CUSTOM_ERROR, "扫码失败"); }
        //     var name = App.HttpContext.GetName();
        //     
        //     sysLoginService.CheckLockUser(name);
        //
        //     TokenModel tokenModel = JwtUtil.GetLoginUser(HttpContext);
        //     if (CacheService.GetScanLogin(dto.Uuid) is not null)
        //     {
        //         Dictionary<string, object> dict = new() { };
        //         dict.Add("status", "success");
        //         dict.Add("token", JwtUtil.GenerateJwtToken(JwtUtil.AddClaims(tokenModel)));
        //         CacheService.SetScanLogin(dto.Uuid, dict);
        //         
        //         return SUCCESS(1);
        //     }
        //     return ToResponse(ResultCode.FAIL, "二维码已失效");
        // }
        #endregion

    }
}
